package com.lin.netty.chat.client;

import com.lin.netty.chat.handler.ClientStateChangeHandler;
import com.lin.netty.chat.message.PingMessage;
import com.lin.netty.chat.protocol.MessageCodec;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.ByteOrder;

@Slf4j
public class ChatClient {
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup workers = new NioEventLoopGroup();
        Channel channel = null;
        try {
            channel = bootstrap.group(workers)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            // 添加handler
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN, 1024, 11, 4, 1, 0, true));
                            pipeline.addLast("logging", new LoggingHandler());
                            pipeline.addLast(new MessageCodec());

                            // 如果3s 没写出数据，会触发IdleState.WRITER_IDLE事件(user event)
                            pipeline.addLast(new IdleStateHandler(0, 30, 0)); // 空闲监测
                            pipeline.addLast(new ChannelDuplexHandler() {
                                // 当用户事件触发时会被调用
                                @Override
                                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                    if (((IdleStateEvent) evt).state() == IdleState.WRITER_IDLE) {
                                        log.debug("3s 没写出数据");
                                        ctx.channel().writeAndFlush(new PingMessage());
                                    }
                                }
                            });

                            pipeline.addLast(new ClientStateChangeHandler()); // 客户端连接状态变更处理器
                        }
                    })
                    .connect(new InetSocketAddress("127.0.0.1", 1122))
                    .sync()
                    .channel();

            channel.closeFuture().sync(); // 阻塞等待关闭
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            workers.shutdownGracefully();
        }

    }
}
